using PlayFab.SharedModels;
using PlayFab.Internal;

namespace PlayFab.Events
{
    public partial class PlayFabEvents
    {
        public delegate void PlayFabErrorEvent(PlayFabRequestCommon request, PlayFabError error);
        public delegate void PlayFabResultEvent<in TResult>(TResult result) where TResult : PlayFabResultCommon;
        public delegate void PlayFabRequestEvent<in TRequest>(TRequest request) where TRequest : PlayFabRequestCommon;
        public event PlayFabErrorEvent OnGlobalErrorEvent;

        private static PlayFabEvents _instance;
        /// <summary>
        /// Private constructor because we call PlayFabEvents.init();
        /// </summary>
        private PlayFabEvents() { }

        public static PlayFabEvents Init()
        {
            if (_instance == null)
            {
                _instance = new PlayFabEvents();
            }
            PlayFabHttp.ApiProcessingEventHandler += _instance.OnProcessingEvent;
            PlayFabHttp.ApiProcessingErrorEventHandler += _instance.OnProcessingErrorEvent;
            return _instance;
        }

        public void UnregisterInstance(object instance)
        {
#if !DISABLE_PLAYFABCLIENT_API
            if (OnLoginResultEvent != null) { foreach (var each in OnLoginResultEvent.GetInvocationList()) { if (ReferenceEquals(each.Target, instance)) { OnLoginResultEvent -= (PlayFabResultEvent<ClientModels.LoginResult>)each; } } }
#endif
<% for (var x = 0; x < apis.length; x++) {
var api = apis[x];
%>#if <%- getApiDefineFlag(api) %><%
for (var i in api.calls) { var apiCall = api.calls[i]; var prefix = ""; if (api.name != "Client"){ prefix=api.name } %>
            if (On<%- prefix %><%- apiCall.name %>RequestEvent != null) { foreach (var each in On<%- prefix%><%- apiCall.name %>RequestEvent.GetInvocationList()) { if (ReferenceEquals(each.Target, instance)) { On<%- prefix%><%- apiCall.name %>RequestEvent -= (PlayFabRequestEvent<<%-api.name%>Models.<%- apiCall.request %>>)each; } } }
<% if (apiCall.result != "LoginResult") { %>            if (On<%- prefix%><%- apiCall.name %>ResultEvent != null) { foreach (var each in On<%- prefix%><%- apiCall.name %>ResultEvent.GetInvocationList()) { if (ReferenceEquals(each.Target, instance)) { On<%- prefix%><%- apiCall.name %>ResultEvent -= (PlayFabResultEvent<<%-api.name%>Models.<%- apiCall.result %>>)each; } } }
<% } } %>
#endif
<% } %>
        }

        private void OnProcessingErrorEvent(PlayFabRequestCommon request, PlayFabError error)
        {
            //This just forwards the event.
            if (_instance.OnGlobalErrorEvent != null)
            {
                _instance.OnGlobalErrorEvent(request, error);
            }
        }

        private void OnProcessingEvent(ApiProcessingEventArgs e)
        {

            if (e.EventType == ApiProcessingEventType.Pre)
            {
                var type = e.Request.GetType();
<% for (var x = 0; x < apis.length; x++){ var api = apis[x];
%>#if <%- getApiDefineFlag(api) %><%
for (var i in api.calls) { var apiCall = api.calls[i]; var prefix = ""; if (api.name != "Client"){ prefix=api.name } %>
                if (type == typeof(<%-api.name%>Models.<%- apiCall.request %>)) { if (_instance.On<%- prefix %><%- apiCall.name %>RequestEvent != null) { _instance.On<%- prefix %><%- apiCall.name %>RequestEvent((<%-api.name%>Models.<%- apiCall.request %>)e.Request); return; } }<% } %>
#endif
<% } %>
            }
            else
            {
                var type = e.Result.GetType();
<% for (var x = 0; x < apis.length; x++){ var api = apis[x];
%>#if <%- getApiDefineFlag(api) %><%
if (api.name=="Client") { %>
                if (type == typeof(ClientModels.LoginResult)) { if (_instance.OnLoginResultEvent != null) { _instance.OnLoginResultEvent((ClientModels.LoginResult)e.Result); return; } }<% } %>
<% for (var i in api.calls) { var apiCall = api.calls[i]; var prefix = ""; if (api.name != "Client"){ prefix=api.name } if (apiCall.result != "LoginResult") { %>
                if (type == typeof(<%-api.name%>Models.<%- apiCall.result %>)) { if (_instance.On<%- prefix %><%- apiCall.name %>ResultEvent != null) { _instance.On<%- prefix %><%- apiCall.name %>ResultEvent((<%-api.name%>Models.<%- apiCall.result %>)e.Result); return; } }<% } } %>
#endif
<% } %>
            }
        }
    }
}
